package at.fhooe.mc;

import java.awt.Color;
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import junit.extensions.abbot.ComponentTestFixture;
import org.easymock.EasyMock;
import org.easymock.IMocksControl;
import org.junit.Before;
import org.junit.Test;
import abbot.finder.ComponentNotFoundException;
import abbot.finder.MultipleComponentsFoundException;
import abbot.finder.matchers.ClassMatcher;
import abbot.tester.JButtonTester;
import abbot.tester.JComboBoxTester;
import abbot.tester.JTextFieldTester;
import at.fhooe.mc.control.ElevatorControlCenter;
import at.fhooe.mc.control.manual.IManualControl;
import at.fhooe.mc.data.ControlMode;
import at.fhooe.mc.data.DirectionType;
import at.fhooe.mc.data.DoorState;
import at.fhooe.mc.data.ElevatorData;
import at.fhooe.mc.data.FloorData;
import at.fhooe.mc.data.SystemData;
import at.fhooe.mc.view.ElevatorControlCenterView;
import at.fhooe.mc.view.JTrianglePanelDown;
import at.fhooe.mc.view.JTrianglePanelSquare;
import at.fhooe.mc.view.JTrianglePanelUp;

public class ElevatorControlCenterViewTest extends ComponentTestFixture
{
	private ElevatorControlCenterView eccView;
	private IMocksControl ctrl;

	private IManualControl mockManual;

	private JButton changeModeButton;
	private JLabel changeModeLabel;
	private JLabel inputTargetFloorLabel;
	private JTextField inputTargetFloorEdit;
	private JButton btnGo;
	private JComboBox comboBoxDirection;
	private JTrianglePanelUp bigUpTriangle;
	private JTrianglePanelDown bigDownTriangle;
	private JTrianglePanelSquare theDoors;

	@Before
	public void setUp() throws ComponentNotFoundException,
		MultipleComponentsFoundException
	{
		ctrl = EasyMock.createStrictControl();
		mockManual = ctrl.createMock(ElevatorControlCenter.class);

		eccView = new ElevatorControlCenterView(mockManual);

		changeModeButton = (JButton) getFinder().find(
			new ClassMatcher(JButton.class)
			{
				public boolean matches(Component c)
				{
					return super.matches(c) && ((JButton) c).getText().equals(
						"Change Mode");
				}
			});

		changeModeLabel = (JLabel) getFinder().find(
			new ClassMatcher(JLabel.class)
			{
				public boolean matches(Component c)
				{
					return super.matches(c) && "changeModeLabel".equals(c.getName());
				}
			});

		inputTargetFloorLabel = (JLabel) getFinder().find(
			new ClassMatcher(JLabel.class)
			{
				public boolean matches(Component c)
				{
					return super.matches(c) && ((JLabel) c).getText().equals(
						"New target :");
				}
			});

		inputTargetFloorEdit = (JTextField) getFinder().find(
			new ClassMatcher(JTextField.class)
			{
				public boolean matches(Component c)
				{
					return super.matches(c) && ((JTextField) c).getText().equals(
						"3");
				}
			});

		btnGo = (JButton) getFinder().find(new ClassMatcher(JButton.class)
		{
			public boolean matches(Component c)
			{
				return super.matches(c) && ((JButton) c).getText().equals(
					"GO!");
			}
		});

		comboBoxDirection = (JComboBox) getFinder().find(
			new ClassMatcher(JComboBox.class)
			{
				public boolean matches(Component c)
				{
					return super.matches(c) && c.getClass() == JComboBox.class;
				}
			});


		bigUpTriangle = (JTrianglePanelUp) getFinder().find(
				new ClassMatcher(JTrianglePanelUp.class)
				{
					public boolean matches(Component c)
					{
						return super.matches(c) && c.getClass() == JTrianglePanelUp.class;
					}
				});

		bigDownTriangle = (JTrianglePanelDown) getFinder().find(
				new ClassMatcher(JTrianglePanelDown.class)
				{
					public boolean matches(Component c)
					{
						return super.matches(c) && c.getClass() == JTrianglePanelDown.class;
					}
				});

		theDoors = (JTrianglePanelSquare) getFinder().find(
				new ClassMatcher(JTrianglePanelSquare.class)
				{
					public boolean matches(Component c)
					{
						return super.matches(c) && c.getClass() == JTrianglePanelSquare.class;
					}
				});
	}

	private SystemData getDefaultSystemData()
	{
		SystemData defaultData = new SystemData();
		defaultData.setClockTick(1000L);
		defaultData.setFloorHeight(20);

		FloorData f = new FloorData();
		f.setFloorIndex(0);
		f.setFloorButtonDown(false);
		f.setFloorButtonUp(true);
		defaultData.getFloors().add(f);

		f = new FloorData();
		f.setFloorIndex(1);
		f.setFloorButtonDown(true);
		f.setFloorButtonUp(false);
		defaultData.getFloors().add(f);

		f = new FloorData();
		f.setFloorIndex(2);
		f.setFloorButtonDown(true);
		f.setFloorButtonUp(true);
		defaultData.getFloors().add(f);

		f = new FloorData();
		f.setFloorIndex(3);
		f.setFloorButtonDown(false);
		f.setFloorButtonUp(false);
		defaultData.getFloors().add(f);

		defaultData.getElevators().add(
			getDefaultElevator(0, ControlMode.AUTOMATIC));

		ElevatorData e = new ElevatorData(4, ControlMode.MANUAL);
		e.setElevatorIndex(1);
		e.setElevatorFloor(1);
		e.setElevatorPosition(2);
		e.setCurrentTarget(0);
		e.setCommittedDirection(DirectionType.DOWN);
		e.setElevatorDoorStatus(DoorState.OPENING);
		e.setElevatorSpeed(0);
		e.setElevatorAccel(-1);
		e.setElevatorCapacity(220);
		e.setElevatorWeight(90);

		e.getElevatorButton()[0] = false;
		e.getElevatorButton()[1] = true;
		e.getElevatorButton()[2] = false;
		e.getElevatorButton()[3] = true;

		e.getServicesFloors()[0] = true;
		e.getServicesFloors()[1] = true;
		e.getServicesFloors()[2] = false;
		e.getServicesFloors()[3] = false;

		defaultData.getElevators().add(e);

		return defaultData;
	}

	public ElevatorData getDefaultElevator(int index, ControlMode mode)
	{
		ElevatorData defaultElevator = new ElevatorData(4, mode);
		defaultElevator.setElevatorIndex(index);
		defaultElevator.setElevatorFloor(2);
		defaultElevator.setElevatorPosition(10);
		defaultElevator.setCurrentTarget(3);
		defaultElevator.setCommittedDirection(DirectionType.UP);
		defaultElevator.setElevatorDoorStatus(DoorState.OPEN);
		defaultElevator.setElevatorSpeed(23);
		defaultElevator.setElevatorAccel(12);
		defaultElevator.setElevatorCapacity(200);
		defaultElevator.setElevatorWeight(100);

		defaultElevator.getElevatorButton()[0] = true;
		defaultElevator.getElevatorButton()[1] = false;
		defaultElevator.getElevatorButton()[2] = true;
		defaultElevator.getElevatorButton()[3] = false;

		defaultElevator.getServicesFloors()[0] = false;
		defaultElevator.getServicesFloors()[1] = false;
		defaultElevator.getServicesFloors()[2] = true;
		defaultElevator.getServicesFloors()[3] = true;

		return defaultElevator;
	}

	@Test
	public void testChangeMode() throws Exception
	{
		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		mockManual.changeControlMode(0, ControlMode.MANUAL);

		ctrl.replay();

		JButtonTester bt = new JButtonTester();
		bt.actionClick(changeModeButton);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		ctrl.verify();
	}

	@Test
	public void testChangeModeTwice() throws Exception
	{
		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		mockManual.changeControlMode(0, ControlMode.MANUAL);
		mockManual.changeControlMode(0, ControlMode.AUTOMATIC);

		ctrl.replay();

		JButtonTester bt = new JButtonTester();
		bt.actionClick(changeModeButton);

		bt.actionClick(changeModeButton);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		ctrl.verify();
	}

	@Test
	public void testChangeModeWithUpdate() throws Exception
	{
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.AUTOMATIC));
		eccView.updateNewValues(data);

		assertFalse(inputTargetFloorLabel.isVisible());
		assertFalse(inputTargetFloorEdit.isVisible());
		assertFalse(btnGo.isVisible());
		assertFalse(comboBoxDirection.isVisible());
		assertEquals("On Auto Mode", changeModeLabel.getText());

		mockManual.changeControlMode(0, ControlMode.MANUAL);

		ctrl.replay();

		JButtonTester bt = new JButtonTester();
		bt.actionClick(changeModeButton);

		assertFalse(inputTargetFloorLabel.isVisible());
		assertFalse(inputTargetFloorEdit.isVisible());
		assertFalse(btnGo.isVisible());
		assertFalse(comboBoxDirection.isVisible());
		assertEquals("On Auto Mode", changeModeLabel.getText());

		data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		ctrl.verify();
	}

	@Test
	public void testChangeModeTwiceWithUpdate() throws Exception
	{
		// init update
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.AUTOMATIC));
		eccView.updateNewValues(data);

		assertFalse(inputTargetFloorLabel.isVisible());
		assertFalse(inputTargetFloorEdit.isVisible());
		assertFalse(btnGo.isVisible());
		assertFalse(comboBoxDirection.isVisible());
		assertEquals("On Auto Mode", changeModeLabel.getText());

		mockManual.changeControlMode(0, ControlMode.MANUAL);
		mockManual.changeControlMode(0, ControlMode.AUTOMATIC);

		ctrl.replay();

		JButtonTester bt = new JButtonTester();

		//button click
		bt.actionClick(changeModeButton);

		//not updated
		assertFalse(inputTargetFloorLabel.isVisible());
		assertFalse(inputTargetFloorEdit.isVisible());
		assertFalse(btnGo.isVisible());
		assertFalse(comboBoxDirection.isVisible());
		assertEquals("On Auto Mode", changeModeLabel.getText());

		data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));

		eccView.updateNewValues(data);

		//updated
		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		bt.actionClick(changeModeButton);

		// not updated
		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.AUTOMATIC));
		eccView.updateNewValues(data);

		//updated
		assertFalse(inputTargetFloorLabel.isVisible());
		assertFalse(inputTargetFloorEdit.isVisible());
		assertFalse(btnGo.isVisible());
		assertFalse(comboBoxDirection.isVisible());
		assertEquals("On Auto Mode", changeModeLabel.getText());

		ctrl.verify();
	}

	@Test
	public void testManualTargetFloor() throws Exception
	{
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		mockManual.manualControl(0, 3);

		ctrl.replay();

		inputTargetFloorEdit.setText("4");

		JButtonTester bt = new JButtonTester();
		bt.actionClick(btnGo);

		data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		data.getElevators().get(0).setCurrentTarget(3);
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		assertEquals("4", inputTargetFloorEdit.getText());

		ctrl.verify();
	}

	/*not implemented yet
	@Test
	public void testManualTargetFloorWithEnterInTextField() throws Exception
	{
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		mockManual.manualControl(0, 3);

		ctrl.replay();

		inputTargetFloorEdit.setText("4");

		JTextFieldTester tester = new JTextFieldTester();
		tester.keyPress(13); //value of enter

		data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		data.getElevators().get(0).setCurrentTarget(3);
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		assertEquals("4", inputTargetFloorEdit.getText());

		ctrl.verify();
	}
	*/

	@Test
	public void testManualDirection() throws Exception
	{
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		data.getElevators().get(0).setCommittedDirection(DirectionType.UP);
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		mockManual.manualDirection(0, DirectionType.DOWN);

		ctrl.replay();

		JComboBoxTester tester = new JComboBoxTester();
		tester.actionSelectItem(comboBoxDirection, DirectionType.DOWN.toString());

		data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		data.getElevators().get(0).setCommittedDirection(DirectionType.DOWN);
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		assertEquals(DirectionType.DOWN, comboBoxDirection.getSelectedItem());

		ctrl.verify();
	}

	@Test
	public void testManualDirectionValueOfCurrentDirectionInt()
	{
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		data.getElevators().get(0).setCommittedDirection(DirectionType.UP);
		eccView.updateNewValues(data);

		assertTrue(eccView.getCurrentDirectionInt() == 0);

		data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		data.getElevators().get(0).setCommittedDirection(DirectionType.DOWN);
		eccView.updateNewValues(data);

		assertTrue(eccView.getCurrentDirectionInt() == 1);

		data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		data.getElevators().get(0).setCommittedDirection(DirectionType.UNCOMMITTED);
		eccView.updateNewValues(data);

		assertTrue(eccView.getCurrentDirectionInt() == 2);
	}

	@Test
	public void testManualDirectionTrianglesUpandDownsColorwhenUp() throws Exception
	{
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		data.getElevators().get(0).setCommittedDirection(DirectionType.UP);
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());
		Thread.sleep(200);	//delay because sometimes it would fail if not
		assertTrue(bigUpTriangle.getTrianglecolor() == Color.lightGray);
		assertTrue(bigDownTriangle.getTrianglecolor() == Color.gray);



	}

	@Test
	public void testManualDirectionTrianglesUpandDownsColorWhenDown() throws Exception
	{
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		data.getElevators().get(0).setCommittedDirection(DirectionType.DOWN);
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());
		Thread.sleep(200); //delay because sometimes it would fail if not
		assertTrue(bigUpTriangle.getTrianglecolor() == Color.gray);
		assertTrue(bigDownTriangle.getTrianglecolor() == Color.lightGray);

	}


	@Test
	public void testDoorStatus() throws Exception
	{
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		data.getElevators().get(0).setElevatorDoorStatus(DoorState.OPEN);
		eccView.updateNewValues(data);

		Thread.sleep(200); //delay because sometimes it would fail if not
		assertTrue(theDoors.getStatusOfDoorsIn() == 1);

		data.getElevators().get(0).setElevatorDoorStatus(DoorState.CLOSING);
		eccView.updateNewValues(data);

		Thread.sleep(200); //delay because sometimes it would fail if not
		assertTrue(theDoors.getStatusOfDoorsIn() == 2);

		data.getElevators().get(0).setElevatorDoorStatus(DoorState.CLOSED);
		eccView.updateNewValues(data);

		Thread.sleep(200); //delay because sometimes it would fail if not
		assertTrue(theDoors.getStatusOfDoorsIn() == 0);

		data.getElevators().get(0).setElevatorDoorStatus(DoorState.OPENING);
		eccView.updateNewValues(data);

		Thread.sleep(200); //delay because sometimes it would fail if not
		assertTrue(theDoors.getStatusOfDoorsIn() == 2);


	}

	@Test
	public void testManualTargetFloorIncorrectFloorInputInvalid() throws Exception
	{
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		ctrl.replay();

		inputTargetFloorEdit.setText("e");

		JButtonTester bt = new JButtonTester();
		bt.actionClick(btnGo);

		ctrl.verify();

		JLabel lbMessage = (JLabel) getFinder().find(new ClassMatcher(JLabel.class)
		{
			public boolean matches(Component c)
			{
				return super.matches(c) && ((JLabel) c).getText().equals(
					"Invalid input, please use a number within the avaiable floors!");
			}
		});

		assertNotNull(lbMessage);
	}


	@Test
	public void testManualTargetFloorIncorrectFloorInputWrongFloor() throws Exception
	{
		SystemData data = getDefaultSystemData();
		data.getElevators().remove(0);
		data.getElevators().set(0, getDefaultElevator(0, ControlMode.MANUAL));
		eccView.updateNewValues(data);

		assertTrue(inputTargetFloorLabel.isVisible());
		assertTrue(inputTargetFloorEdit.isVisible());
		assertTrue(btnGo.isVisible());
		assertTrue(comboBoxDirection.isVisible());
		assertEquals("On Manual Mode", changeModeLabel.getText());

		ctrl.replay();

		inputTargetFloorEdit.setText("11");

		JButtonTester bt = new JButtonTester();
		bt.actionClick(btnGo);

		ctrl.verify();

		JLabel lbMessage = (JLabel) getFinder().find(new ClassMatcher(JLabel.class)
		{
			public boolean matches(Component c)
			{
				return super.matches(c) && ((JLabel) c).getText().equals(
					"Invalid input, the number you have choosen is not within the avaiable floors!");
			}
		});

		assertNotNull(lbMessage);
	}

}
